﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Web.Configuration;
using System.Web.UI.Design;
using System.Windows.Forms.Design;
using System.Configuration;

namespace Ajaxna.Designers
{
    public class WebConfigAction
    {
        // Fields
        private IComponent _component;
        private System.Configuration.Configuration _configuration;
        private HttpHandlersSection _httpHandlers;
        private HttpModulesSection _httpModules;
        private bool _isReadOnlyConfiguration = true;

        // Methods
        public WebConfigAction(IComponent component)
        {
            this._component = component;
        }

        public bool AddHandler(string path, Type type, string verb)
        {
            this.EnsureWritableConfiguration();
            this.HttpHandlers.Handlers.Add(new HttpHandlerAction(path, type.AssemblyQualifiedName, verb, false));
            return this.TrySave(string.Format("Access to Web.Config is denied. Please, manually add the \"{0}\" HttpHandler. <add path=\"{0}\" verb=\"{2}\" type=\"{1}\" validate=\"false\" />", path, type.AssemblyQualifiedName, verb));
        }

        public void AddModule(string name, Type type)
        {
            this.EnsureWritableConfiguration();
            this.HttpModules.Modules.Add(new HttpModuleAction(name, type.AssemblyQualifiedName));
            this.TrySave(string.Format("Access to Web.Config is denied. Please, manually add the \"{0}\" HttpModule. <add name=\"{0}\" type=\"{1}\" />", name, type.AssemblyQualifiedName));
        }

        private void EnsureWritableConfiguration()
        {
            if (this.IsReadOnlyConfiguration)
            {
                this.InitConfiguration(false);
            }
        }

        public bool HandlerExists(string path, Type type, string verb)
        {
            int index = this.HttpHandlers.Handlers.IndexOf(new HttpHandlerAction(path, type.AssemblyQualifiedName, verb, false));
            return ((index != -1) && (this.HttpHandlers.Handlers[index].Type == type.AssemblyQualifiedName));
        }

        private void InitConfiguration(bool isReadOnly)
        {
            IWebApplication service = (IWebApplication)this.Component.Site.GetService(typeof(IWebApplication));
            service.GetProjectItemFromUrl("~/Web.Config");
            this._isReadOnlyConfiguration = isReadOnly;
            this._httpHandlers = null;
            this._httpModules = null;
            this._configuration = service.OpenWebConfiguration(isReadOnly);
        }

        public bool ModuleExists(string name, Type type)
        {
            HttpModuleAction action = new HttpModuleAction(name, type.AssemblyQualifiedName);
            return (this.HttpModules.Modules.IndexOf(action) != -1);
        }

        public void RemoveHandler(string path)
        {
            this.EnsureWritableConfiguration();
            for (int i = this.HttpHandlers.Handlers.Count - 1; i > 0; i--)
            {
                HttpHandlerAction action = this.HttpHandlers.Handlers[i];
                if (action.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase))
                {
                    this.HttpHandlers.Handlers.RemoveAt(i);
                }
                this.TrySave(string.Format("Access to Web.Config is denied. Please, manually remove the \"{0}\" HttpHandler. <add path=\"{0}\" verb=\"{2}\" type=\"{1}\" validate=\"false\" />", path, action.Type, action.Verb));
            }
        }

        public void RemoveHandler(string path, Type type, string verb)
        {
            this.EnsureWritableConfiguration();
            int index = this.HttpHandlers.Handlers.IndexOf(new HttpHandlerAction(path, type.AssemblyQualifiedName, verb, false));
            if (index > -1)
            {
                this.HttpHandlers.Handlers.RemoveAt(index);
                this.TrySave(string.Format("Access to Web.Config is denied. Please, manually remove the \"{0}\" HttpHandler. <add path=\"{0}\" verb=\"{2}\" type=\"{1}\" validate=\"false\" />", path, type.AssemblyQualifiedName, verb));
            }
        }

        public void RemoveModule(string name)
        {
            this.EnsureWritableConfiguration();
            for (int i = this.HttpModules.Modules.Count - 1; i > 0; i--)
            {
                HttpModuleAction action = this.HttpModules.Modules[i];
                if (action.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                {
                    this.HttpModules.Modules.RemoveAt(i);
                    this.TrySave(string.Format("Access to Web.Config is denied. Please, manually remove the HttpModule <add name=\"{0}\" type=\"{1}\" />", name, action.Type));
                }
            }
        }

        public void RemoveModule(string name, Type type)
        {
            this.EnsureWritableConfiguration();
            int index = this.HttpModules.Modules.IndexOf(new HttpModuleAction(name, type.AssemblyQualifiedName));
            if (index > -1)
            {
                this.HttpModules.Modules.RemoveAt(index);
                this.TrySave(string.Format("Access to Web.Config is denied. Please, manually remove the HttpModule <add name=\"{0}\" type=\"{1}\" />", name, type.AssemblyQualifiedName));
            }
        }

        internal void ShowMessage(string text)
        {
            IUIService service = (IUIService)this.Component.Site.GetService(typeof(IUIService));
            if (service != null)
            {
                service.ShowMessage(text);
            }
        }

        protected bool TrySave(string errorMessage)
        {
            this.EnsureWritableConfiguration();
            try
            {
                this.Configuration.Save();
            }
            catch
            {
                this.ShowMessage(errorMessage);
                return false;
            }
            return true;
        }

        // Properties
        protected IComponent Component
        {
            get
            {
                return this._component;
            }
        }

        private System.Configuration.Configuration Configuration
        {
            get
            {
                if (this._configuration == null)
                {
                    this.InitConfiguration(true);
                }
                return this._configuration;
            }
        }

        private HttpHandlersSection HttpHandlers
        {
            get
            {
                if (this._httpHandlers == null)
                {
                    ConfigurationSectionGroup sectionGroup = this.Configuration.GetSectionGroup("system.web");
                    this._httpHandlers = (HttpHandlersSection)sectionGroup.Sections["httpHandlers"];
                }
                return this._httpHandlers;
            }
        }

        private HttpModulesSection HttpModules
        {
            get
            {
                if (this._httpModules == null)
                {
                    ConfigurationSectionGroup sectionGroup = this.Configuration.GetSectionGroup("system.web");
                    this._httpModules = (HttpModulesSection)sectionGroup.Sections["httpModules"];
                }
                return this._httpModules;
            }
        }

        private bool IsReadOnlyConfiguration
        {
            get
            {
                return this._isReadOnlyConfiguration;
            }
        }
    } 
}
